home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / AppsToGo / Kibitz / File.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-22  |  22.8 KB  |  868 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:            file.c
  5. ** Some code from:  Traffic Light 2.0 version, by Keith Rollin & John Harvey
  6. ** Modified by:     Eric Soldan
  7. **
  8. ** Copyright © 1990-1992 Apple Computer, Inc.
  9. ** All rights reserved. */
  10.  
  11.  
  12.  
  13. /*****************************************************************************/
  14.  
  15.  
  16.  
  17. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  18. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  19. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  20.  
  21. #ifndef __ALIASES__
  22. #include <Aliases.h>
  23. #endif
  24.  
  25. #ifndef __ERRORS__
  26. #include <Errors.h>
  27. #endif
  28.  
  29. #ifndef __MEMORY__
  30. #include <Memory.h>
  31. #endif
  32.  
  33. #ifndef __PACKAGES__
  34. #include <Packages.h>
  35. #endif
  36.  
  37. #ifndef __TOOLUTILS__
  38. #include <ToolUtils.h>
  39. #endif
  40.  
  41. #ifndef __UTILITIES__
  42. #include <Utilities.h>
  43. #endif
  44.  
  45.  
  46.  
  47. /*****************************************************************************/
  48.  
  49.  
  50.  
  51. static Boolean    gIncNewFileNumFlag = true;
  52.  
  53.  
  54.  
  55. /*****************************************************************************/
  56. /*****************************************************************************/
  57.  
  58. #ifdef applec
  59. #pragma segment File
  60. #endif
  61.  
  62. /*****************************************************************************/
  63. /*****************************************************************************/
  64.  
  65.  
  66.  
  67. /* This function disposes of the document.  It checks to see if a file is
  68. ** currently open for the document.  If it is, then the document is closed.
  69. ** Once there is no open file for the document, the memory occupied by the
  70. ** document is released. */
  71.  
  72. OSErr    AppDisposeDocument(FileRecHndl frHndl)
  73. {
  74.     OSErr        err;
  75.     Handle        snd;
  76.  
  77.     err = noErr;
  78.  
  79.     if (frHndl) {
  80.         SetOpponentType(frHndl, kOnePlayer);
  81.             /* Disconnect from opponent. */
  82.  
  83.         if ((*frHndl)->fileState.fss.vRefNum != kInvalVRefNum)
  84.             err = FSClose((*frHndl)->fileState.refNum);
  85.                 /* Close the file, if opened. */
  86.  
  87.         DisposeHandle((Handle)(*frHndl)->doc.legalMoves);
  88.         DisposeHandle((Handle)(*frHndl)->doc.gameMoves);
  89.         snd = (*frHndl)->doc.sound;
  90.         if (snd)
  91.             DisposeHandle(snd);
  92.                 /* Release all handles hanging off the document. */
  93.  
  94.         DisposeHandle((Handle)frHndl);
  95.             /* Release memory for the document handle. */
  96.     }
  97.  
  98.     return(err);
  99. }
  100.  
  101.  
  102.  
  103. /*****************************************************************************/
  104.  
  105.  
  106.  
  107. /* This function returns whether or not the document is dirty. */
  108.  
  109. Boolean    AppDocumentDirty(FileRecHndl frHndl)
  110. {
  111.     return((*frHndl)->fileState.docDirty);
  112. }
  113.  
  114.  
  115.  
  116. /*****************************************************************************/
  117.  
  118.  
  119.  
  120. /* This function creates a new document.  A handle is created as the
  121. ** reference to the document.  Header information is placed in this handle.
  122. ** The application-specific data follows this header information.  The
  123. ** handle is returned (or nil upon failure), and typically the handle is
  124. ** then stored in the refCon field of the window.  Note that this is a
  125. ** convention, and is not mandatory.  This allows a document to exist that
  126. ** has no window.  A document with no window is useful when the application
  127. ** is called from the finder in response to a print request.  The document
  128. ** can be loaded and printed without involving a window on the screen. */
  129.  
  130.  
  131. OSErr    AppNewDocument(FileRecHndl *returnHndl, short winNameType)
  132. {
  133.     static short    untitledCount;
  134.     FileRecHndl        frHndl;
  135.     FileRecPtr        frPtr;
  136.     Str255            untitled;
  137.     StringPtr        pstr;
  138.     MoveListHndl    legalMovesHndl;
  139.     GameListHndl    gameMovesHndl;
  140.  
  141.     *returnHndl = nil;
  142.  
  143.     frHndl = (FileRecHndl)NewHandle(sizeof(FileRec));
  144.     if (frHndl) {
  145.  
  146.         GetIndString(untitled, rMiscStrings, winNameType);
  147.         frPtr = *frHndl;
  148.         frPtr->fileState.docDirty    = false;
  149.         frPtr->fileState.readOnly    = false;
  150.         frPtr->fileState.fss.vRefNum = kInvalVRefNum;
  151.         frPtr->fileState.window      = nil;
  152.         pstr = frPtr->fileState.fss.name;
  153.         pcpy(pstr, untitled);
  154.         if (gIncNewFileNumFlag) ++untitledCount;
  155.         pcatdec(pstr, untitledCount);
  156.  
  157.         legalMovesHndl = (MoveListHndl)NewHandle(0);
  158.         if (!legalMovesHndl) {
  159.             DisposeHandle((Handle)frHndl);
  160.             return(memFullErr);
  161.         }
  162.  
  163.         gameMovesHndl = (GameListHndl)NewHandle(0);
  164.         if (!gameMovesHndl) {
  165.             DisposeHandle((Handle)frHndl);
  166.             DisposeHandle((Handle)legalMovesHndl);
  167.             return(memFullErr);
  168.         }
  169.  
  170.         NewGame(frHndl);        /* Initialize the game. */
  171.  
  172.         frPtr = *frHndl;
  173.         frPtr->doc.legalMoves = legalMovesHndl;
  174.         frPtr->doc.gameMoves  = gameMovesHndl;
  175.         if (winNameType == ksMssgName) frPtr->doc.myColor = kMessageDoc;
  176.  
  177.         *returnHndl = frHndl;
  178.         return(noErr);            /* All is well. */
  179.     }
  180.  
  181.     return(memFullErr);
  182. }
  183.  
  184.  
  185.  
  186. /*****************************************************************************/
  187.  
  188.  
  189.  
  190. OSErr    AppOpenDocument(FileRecHndl *result, FSSpecPtr fileToOpen, char permission)
  191. {
  192.     StandardFileReply    reply;
  193.     short                fileRefNum;
  194.     FileRecHndl            frHndl;
  195.     OSErr                err;
  196.     FSSpec                myFileSpec;
  197.     DialogPtr            openDialog;
  198.     short                item, winNameType;
  199.  
  200.     *result = nil;        /* Assume we will fail. */
  201.  
  202.     if (!fileToOpen) {
  203.         if (DisplayGetFile(&reply))        /* Let the user decide which file. */
  204.             myFileSpec = reply.sfFile;    /* User's choice.                   */
  205.         else
  206.             return(userCanceledErr);    /* User canceled. */
  207.     }
  208.     else
  209.         myFileSpec = *fileToOpen;        /* Pre-designated file to open. */
  210.  
  211.     winNameType = ksOrigName;
  212.     if (reply.sfType != gameFileType) winNameType = ksMssgName;
  213.  
  214.     IncNewFileNum(false);
  215.     err = AppNewDocument(&frHndl, winNameType);
  216.     IncNewFileNum(true);
  217.     if (err) return(err);
  218.         /* We couldn't create an empty document, so give it up. */
  219.  
  220.     err = HOpen(myFileSpec.vRefNum, myFileSpec.parID,
  221.                 myFileSpec.name, permission, &fileRefNum);
  222.  
  223.     if (err == opWrErr) {
  224.  
  225.         ParamText(myFileSpec.name, nil, nil, nil);
  226.         openDialog = GetCenteredDialog(rOpenReadOnly, nil, nil, (WindowPtr)-1L);
  227.         if (!openDialog) {
  228.             AppDisposeDocument(frHndl);
  229.             return(err);
  230.         }
  231.  
  232.         OutlineDialogItem(openDialog, kOpenYes);
  233.         DoSetCursor(&qd.arrow);
  234.         ModalDialog(gKeyEquivFilterUPP, &item);
  235.         DisposeDialog(openDialog);
  236.         if (item != kOpenYes) return(userCanceledErr);
  237.  
  238.         (*frHndl)->fileState.readOnly = true;
  239.         err = HOpen(myFileSpec.vRefNum, myFileSpec.parID,
  240.                     myFileSpec.name, fsRdPerm, &fileRefNum);
  241.     }
  242.  
  243.     if (err) {
  244.         AppDisposeDocument(frHndl);
  245.         return(err);
  246.     }
  247.  
  248.     (*frHndl)->fileState.fss    = myFileSpec;
  249.     (*frHndl)->fileState.refNum = fileRefNum;
  250.  
  251.     err = AppReadDocument(frHndl, reply.sfType);
  252.     if (err) {
  253.         AppDisposeDocument(frHndl);
  254.         return(err);
  255.     }
  256.  
  257.     if ((*frHndl)->fileState.readOnly) {
  258.         FSClose((*frHndl)->fileState.refNum);
  259.         (*frHndl)->fileState.fss.vRefNum = kInvalVRefNum;
  260.     }        /* If it's read-only, we don't need the file left open. */
  261.  
  262.     *result = frHndl;
  263.     return(err);
  264. }
  265.  
  266.  
  267.  
  268. /*****************************************************************************/
  269.  
  270.  
  271.  
  272. OSErr    AppSaveDocument(FileRecHndl frHndl, WindowPtr window, short saveMode)
  273. {
  274.     Str255                closeOrQuit;
  275.     short                item, gameStatus;
  276.     StandardFileReply    reply;
  277.     OSErr                err;
  278.     short                fileRefNum;
  279.     DialogPtr            saveDialog;
  280.     Boolean                doPrompt;
  281.     Boolean                youLose;
  282.     OSType                theFileType;
  283.  
  284. /*    When entering, saveMode is set to the menu command number of the
  285. **    the item that prompted this.  Current settings are iSave, iSaveAs,
  286. **    iClose, and iQuit. */
  287.  
  288.     if (saveMode != iSaveAs) {                        /* If regular save... */
  289.         if (!AppDocumentDirty(frHndl))                /* If file clean...   */
  290.             return(noErr);                            /* Consider it saved. */
  291.     }
  292.  
  293.     pcpy(reply.sfFile.name, (*frHndl)->fileState.fss.name);
  294.  
  295.     if ((saveMode == iClose) || (saveMode == iQuit)) {
  296.         /* If implicit save... */
  297.  
  298.         GetIndString(closeOrQuit, rMiscStrings,
  299.                      (saveMode == iClose) ? ksClosing : ksQuitting);
  300.         ParamText(reply.sfFile.name, closeOrQuit, nil, nil);
  301.  
  302.         gameStatus = GameStatus(frHndl);
  303.         youLose = ((gameStatus == kYouLose) || (gameStatus == kYouLoseOnTime));
  304.         if ((gameStatus == kWhiteResigns) && ((*frHndl)->doc.myColor == WHITE))
  305.             youLose = true;
  306.         if ((gameStatus == kBlackResigns) && ((*frHndl)->doc.myColor == BLACK))
  307.             youLose = true;
  308.         if (youLose)
  309.             saveDialog = GetCenteredDialog(rNoYesCancel, nil, window, (WindowPtr)-1L);
  310.         else
  311.             saveDialog = GetCenteredDialog(rYesNoCancel, nil, window, (WindowPtr)-1L);
  312.  
  313.         if (saveDialog) {
  314.             OutlineDialogItem(saveDialog, kSaveYes);
  315.             DoSetCursor(&qd.arrow);
  316.             ModalDialog(gKeyEquivFilterUPP, &item);
  317.             DisposeDialog(saveDialog);
  318.             if (youLose)
  319.                 if (item != kSaveCanceled)
  320.                     item = (item == kSaveYes) ? kSaveNo : kSaveYes;
  321.         }
  322.         else
  323.             item = kSaveYes;
  324.  
  325.         if (item != kSaveYes) {
  326.             err = noErr;
  327.             if (item == kSaveCanceled) err = userCanceledErr;
  328.             return(err);
  329.         }
  330.     }
  331.  
  332.     doPrompt = (
  333.         (saveMode == iSaveAs) ||
  334.         ((*frHndl)->fileState.fss.vRefNum == kInvalVRefNum)
  335.     );
  336.  
  337.     if (doPrompt) {
  338.         /* Prompt with SFGetFile if doing a Save As or have never saved before. */
  339.  
  340.         if (!DisplayPutFile(&reply))
  341.             return(userCanceledErr);
  342.                 /* User canceled the save. */
  343.  
  344.         if ((*frHndl)->fileState.fss.vRefNum != kInvalVRefNum)
  345.             FSClose((*frHndl)->fileState.refNum);
  346.                 /* Close the old file.  Don't respond to any error here because
  347.                 ** the user may be trying to do a save-as because their old file
  348.                 ** is bad.  If we fail to close the old file, and then respond
  349.                 ** to the error, the user won't get the opportunity to save
  350.                 ** their document to a new file.
  351.                 */
  352.  
  353.         theFileType = gameFileType;
  354.         if ((*frHndl)->doc.myColor == kMessageDoc) theFileType = mssgFileType;
  355.  
  356.         err = Create_OpenFile(&reply.sfFile, &fileRefNum, theFileType);
  357.         if (err) {
  358.             (*frHndl)->fileState.fss.vRefNum = kInvalVRefNum;
  359.             return(err);
  360.         }
  361.  
  362.         (*frHndl)->fileState.fss    = reply.sfFile;
  363.         (*frHndl)->fileState.refNum = fileRefNum;
  364.             /* This is the new file. */
  365.  
  366.         if (window) AppNewWindowTitle(window);
  367.     }
  368.  
  369.     err = AppWriteDocument(frHndl);
  370.     if (err)
  371.         return(err);
  372.  
  373.     (*frHndl)->fileState.docDirty = false;
  374.     (*frHndl)->fileState.readOnly = false;
  375.     return(noErr);
  376. }
  377.  
  378.  
  379.  
  380. /*****************************************************************************/
  381.  
  382.  
  383.  
  384. /* ConvertOldToNewSFReply
  385. **
  386. ** struct StandardFileReply {            struct SFReply {
  387. **     Boolean     sfGood;                <-    Boolean good;
  388. **     Boolean     sfReplacing;        <-    Boolean copy;
  389. **     OSType         sfType;                <-    OSType fType;
  390. **     FSSpec        sfFile;
  391. **                     vRefNum;        <-    real vRefnum from (short vRefNum)
  392. **                     parID;            <-    real dirID from (short vRefNum)
  393. **                     name;            <-    Str63 fName;
  394. **     ScriptCode    sfScript;            <-    iuSystemScript
  395. **     short         sfFlags;            <-    0
  396. **     Boolean     sfIsFolder;            <-    false
  397. **     Boolean     sfIsVolume;            <-    false
  398. **     long        sfReserved1;        <-    0
  399. **     short        sfReserved2;        <-    0
  400. ** };
  401. **}; */
  402.  
  403. void    ConvertOldToNewSFReply(SFReply *oldReply, StandardFileReply *newReply)
  404. {
  405.     OSErr    err;
  406.     long    ignoredProcID;
  407.  
  408.     newReply->sfGood        = oldReply->good;
  409.     newReply->sfReplacing    = oldReply->copy;        /* Correct assignment? */
  410.     newReply->sfType        = oldReply->fType;
  411.  
  412.     err = GetWDInfo(oldReply->vRefNum,
  413.                     &newReply->sfFile.vRefNum,
  414.                     &newReply->sfFile.parID,
  415.                     &ignoredProcID);
  416.     BlockMove((Ptr)&oldReply->fName,
  417.               (Ptr)&newReply->sfFile.name,
  418.               oldReply->fName[0]+1);
  419.  
  420.     /* Punt on the rest. */
  421.     newReply->sfScript        = iuSystemScript;
  422.     newReply->sfFlags        = 0;
  423.     newReply->sfIsFolder    = false;
  424.     newReply->sfIsVolume    = false;
  425.     newReply->sfReserved1    = 0;
  426.     newReply->sfReserved2    = 0;
  427. }
  428.  
  429.  
  430.  
  431. /*****************************************************************************/
  432.  
  433.  
  434.  
  435. /* Create_OpenFile
  436. **
  437. ** Opens the file specified by the passed FSSpec, creating it if it doesn't
  438. ** already exist. Refturns the refnum of the open file to the application.
  439. ** File Manager errors are reported and returned. */
  440.  
  441. OSErr    Create_OpenFile(FSSpec *file, short *refNum, OSType theFileType)
  442. {
  443.     OSErr    err;
  444.  
  445.     err = HCreate(file->vRefNum, file->parID, file->name, gameCreator, theFileType);
  446.     if (err == dupFNErr) {
  447.  
  448.         /* The user already told Standard File to replace the old file
  449.            so let's get rid of it. */
  450.  
  451.         HDelete(file->vRefNum, file->parID, file->name);
  452.  
  453.         /* Try creating it again. */
  454.         err = HCreate(file->vRefNum, file->parID, file->name, gameCreator, theFileType);
  455.     }
  456.  
  457.     if (!err) {
  458.         err = HOpen(file->vRefNum, file->parID, file->name, fsRdWrPerm, refNum);
  459.         if (err)
  460.             HDelete(file->vRefNum, file->parID, file->name);
  461.     }
  462.  
  463.     return(err);
  464. }
  465.  
  466.  
  467.  
  468. /*****************************************************************************/
  469.  
  470.  
  471.  
  472. /* DisplayGetFile
  473. **
  474. ** Simple routine to display a list of files with our file type. */
  475.  
  476. Boolean DisplayGetFile(StandardFileReply *reply)
  477. {
  478.     SFTypeList    typeList = {gameFileType, mssgFileType, typeChar};
  479.     Point        where = {100, 100};
  480.     SFReply        oldReply;
  481.  
  482.     if (gSystemVersion >= 0x0700)    /* If new standard file available... */
  483.         StandardGetFile(nil, 3, typeList, reply);
  484.  
  485.     else {
  486.         SFGetFile(where, "\pSelect a document to open.",
  487.                          nil, 3, typeList, nil, &oldReply);
  488.  
  489.         ConvertOldToNewSFReply(&oldReply, reply);
  490.     }
  491.  
  492.     return(reply->sfGood);
  493. }
  494.  
  495.  
  496.  
  497. /*****************************************************************************/
  498.  
  499.  
  500.  
  501. /* DisplayPutFile
  502. **
  503. ** Displays the StandardFile PutFile dialog box. Fills out the passed reply
  504. ** record, and returns the sfGood field as a result. */
  505.  
  506. Boolean DisplayPutFile(StandardFileReply *reply)
  507. {
  508.     Str255        prompt;
  509.     Point        where = {100, 100};
  510.     SFReply        oldReply;
  511.  
  512.     GetIndString(prompt, rMiscStrings, ksSFprompt);
  513.  
  514.     if (gSystemVersion >= 0x0700)    /* If new standard file available... */
  515.         StandardPutFile(prompt, reply->sfFile.name, reply);
  516.     else {
  517.         SFPutFile(where, prompt, reply->sfFile.name, nil, &oldReply);
  518.         ConvertOldToNewSFReply(&oldReply, reply);
  519.     }
  520.  
  521.     return(reply->sfGood);
  522. }
  523.  
  524.  
  525.  
  526. /*****************************************************************************/
  527.  
  528.  
  529.  
  530. void    IncNewFileNum(Boolean flag)
  531. {
  532.     gIncNewFileNumFlag = flag;
  533. }
  534.  
  535.  
  536.  
  537. /*****************************************************************************/
  538. /*****************************************************************************/
  539. /*****************************************************************************/
  540.  
  541.  
  542.  
  543. /* AppReadDocument
  544. **
  545. ** Reads in specified file into the data portion of a document handle. */
  546.  
  547. OSErr    AppReadDocument(FileRecHndl frHndl, OSType ftype)
  548. {
  549.     short            fileRefNum, vers, i;
  550.     OSErr            err;
  551.     char            hstate;
  552.     Ptr                ptr1, ptr2;
  553.     long            count;
  554.     GameListHndl    gameMovesHndl;
  555.     Handle            textHndl;
  556.  
  557.     fileRefNum = (*frHndl)->fileState.refNum;
  558.  
  559.     err = SetFPos(fileRefNum, fsFromStart, 0);
  560.         /* Set the file position to the beginning of the file. */
  561.  
  562.     if (ftype != typeChar) {
  563.         if (!err) {        /* Read board info from file. */
  564.             hstate = LockHandleHigh((Handle)frHndl);
  565.             ptr1   = (Ptr)&((*frHndl)->doc);
  566.             ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo1);
  567.             count  = (long)ptr2 - (long)ptr1;
  568.             err    = FSRead(fileRefNum, &count, ptr1);
  569.             HSetState((Handle)frHndl, hstate);
  570.             vers = (*frHndl)->doc.version;
  571.             if ((vers > kVersion) | (vers < kLeastVersion)) err = vers;
  572.         }
  573.  
  574.         if (!err) {
  575.             switch (vers) {
  576.                 case kLeastVersion:
  577.                     (*frHndl)->doc.version = kVersion;
  578.                     break;
  579.                 case kVersion:
  580.                     hstate = LockHandleHigh((Handle)frHndl);
  581.                     ptr1   = (Ptr)&((*frHndl)->doc.reconnectZone);
  582.                     ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo2);
  583.                     count  = (long)ptr2 - (long)ptr1;
  584.                     err    = FSRead(fileRefNum, &count, ptr1);
  585.                     HSetState((Handle)frHndl, hstate);
  586.                     (*frHndl)->doc.compMovesWhite = (*frHndl)->doc.keepCMWhite;
  587.                     (*frHndl)->doc.compMovesBlack = (*frHndl)->doc.keepCMBlack;
  588.                     if ((*frHndl)->doc.timeLeft[0] != -1)
  589.                         for (i = 0; i < 2; ++i)
  590.                             (*frHndl)->doc.timeLeft[i] = (*frHndl)->doc.defaultTime[i];
  591.                     break;
  592.             }
  593.         }
  594.  
  595.         if (!err) {        /* Read move info from file. */
  596.             gameMovesHndl = (*frHndl)->doc.gameMoves;
  597.             count         = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  598.             SetHandleSize((Handle)gameMovesHndl, count);
  599.             err = MemError();
  600.             if (!err) {
  601.                 hstate = LockHandleHigh((Handle)gameMovesHndl);
  602.                 err = FSRead(fileRefNum, &count, (Ptr)(*gameMovesHndl));
  603.                 HSetState((Handle)gameMovesHndl, hstate);
  604.                 (*frHndl)->doc.timerRefTick = TickCount();
  605.                 (*frHndl)->doc.displayTime[0] = -1;
  606.                 (*frHndl)->doc.displayTime[1] = -1;
  607.                 (*frHndl)->doc.freezeTime[0] = -1;
  608.                 (*frHndl)->doc.freezeTime[1] = -1;
  609.                 (*frHndl)->fileState.docDirty = false;
  610.                 if (!err)
  611.                     if ((*frHndl)->doc.version != kVersion)
  612.                         err = kWrongVersion;
  613.             }
  614.         }
  615.     }
  616.  
  617.     if (!err) {        /* Read TextEdit text from file. */
  618.         textHndl = (Handle)(*frHndl)->doc.legalMoves;
  619.             /* There may be text saved to the file.  If there is any, this text
  620.             ** belongs in the out-box TextEdit control.  AppNewWindow creates
  621.             ** this control.  The problem is that a document is read before the
  622.             ** window for it is created.  Therefore the text will be placed
  623.             ** temporarily in the legalMoves handle.  Once GenerateLegalMoves
  624.             ** is called, the content of this handle will be overwritten.
  625.             ** GenereteLegalMoves isn't called until the window is created, so
  626.             ** this is an easy way to pass the text to AppNewWindow. */
  627.         count = 32000;
  628.             /* The size of the text isn't saved to disk.  This is the maximum
  629.             ** that we will accept. */
  630.         SetHandleSize(textHndl, count);
  631.         if (!(err = MemError())) {
  632.             hstate = LockHandleHigh(textHndl);
  633.             err    = FSRead(fileRefNum, &count, *textHndl);
  634.             HSetState((Handle)frHndl, hstate);
  635.             if (err == eofErr) err = noErr;
  636.             if (err) count = 0;
  637.             SetHandleSize(textHndl, count);
  638.                 /* Set the handle to the actual size of the text on disk. */
  639.         }
  640.     }
  641.  
  642.     return(err);
  643. }
  644.  
  645.  
  646.  
  647. /*****************************************************************************/
  648.  
  649.  
  650.  
  651. /* AppWriteDocument
  652. **
  653. ** Writes the data portion of a document handle to the specified file. */
  654.  
  655. OSErr    AppWriteDocument(FileRecHndl frHndl)
  656. {
  657.     short            fileRefNum;
  658.     OSErr            err;
  659.     char            hstate;
  660.     Ptr                ptr1, ptr2;
  661.     long            count, fpos;
  662.     GameListHndl    gameMovesHndl;
  663.     TEHandle        te;
  664.     Handle            textHndl;
  665.     WindowPtr        window;
  666.     short            width;
  667.  
  668.     fileRefNum = (*frHndl)->fileState.refNum;
  669.  
  670.     err = SetFPos(fileRefNum, fsFromStart, 0);
  671.         /* Set the file position to the beginning of the file. */
  672.  
  673.     if (!err) {        /* Write board info to file. */
  674.         hstate = LockHandleHigh((Handle)frHndl);
  675.         ptr1   = (Ptr)&((*frHndl)->doc);
  676.         ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo1);
  677.         count  = (long)ptr2 - (long)ptr1;
  678.         err    = FSWrite(fileRefNum, &count, ptr1);
  679.         HSetState((Handle)frHndl, hstate);
  680.     }
  681.  
  682.     if (!err) {        /* Write board info to file. */
  683.         hstate = LockHandleHigh((Handle)frHndl);
  684.         (*frHndl)->doc.reconnectZone[0]    = 0;
  685.         (*frHndl)->doc.reconnectMachine[0] = 0;
  686.         if ((*frHndl)->doc.twoPlayer) {
  687.             pcpy((*frHndl)->doc.reconnectZone,    (*frHndl)->doc.opponentZone);
  688.             pcpy((*frHndl)->doc.reconnectMachine, (*frHndl)->doc.opponentMachine);
  689.         }
  690.         (*frHndl)->doc.justBoardWindow = false;
  691.         window = (*frHndl)->fileState.window;
  692.         if (window) {
  693.             width = window->portRect.right - window->portRect.left;
  694.             if (width == rJustBoardWindowWidth) (*frHndl)->doc.justBoardWindow = true;
  695.         }
  696.         (*frHndl)->doc.keepCMWhite = (*frHndl)->doc.compMovesWhite;
  697.         (*frHndl)->doc.keepCMBlack = (*frHndl)->doc.compMovesBlack;
  698.         ptr1  = (Ptr)&((*frHndl)->doc.reconnectZone);
  699.         ptr2  = (Ptr)&((*frHndl)->doc.endFileInfo2);
  700.         count = (long)ptr2 - (long)ptr1;
  701.         err   = FSWrite(fileRefNum, &count, ptr1);
  702.         HSetState((Handle)frHndl, hstate);
  703.     }
  704.  
  705.     if (!err) {        /* Write move info to file. */
  706.         gameMovesHndl = (*frHndl)->doc.gameMoves;
  707.         count         = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  708.         hstate = LockHandleHigh((Handle)gameMovesHndl);
  709.         err = FSWrite(fileRefNum, &count, (Ptr)(*gameMovesHndl));
  710.         HSetState((Handle)gameMovesHndl, hstate);
  711.     }
  712.  
  713.     if (!err) {        /* Write out-box TextEdit control text to file. */
  714.         te       = (*frHndl)->doc.message[kMessageOut];
  715.         textHndl = (*te)->hText;
  716.         count    = (*te)->teLength;
  717.         hstate   = LockHandleHigh(textHndl);
  718.         err      = FSWrite(fileRefNum, &count, *textHndl);
  719.         HSetState(textHndl, hstate);
  720.     }
  721.  
  722.     if (!err) {
  723.         err = GetFPos(fileRefNum, &fpos);
  724.         if (!err) err = SetEOF(fileRefNum, fpos);
  725.     }
  726.  
  727.     return(err);
  728. }
  729.  
  730.  
  731.  
  732. /*****************************************************************************/
  733.  
  734.  
  735.  
  736. OSErr    AppDuplicateDocument(FileRecHndl oldFrHndl, FileRecHndl *newFrHndl)
  737. {
  738.     OSErr            err;
  739.     GameListHndl    oldMoves, newMoves;
  740.     Ptr                ptr1, ptr2;
  741.     long            oldMovesSize, dataSize;
  742.     Handle            oldText, newText;
  743.     TEHandle        te;
  744.     short            winNameType;
  745.  
  746.     winNameType = ksOrigName;
  747.     if ((*oldFrHndl)->doc.myColor == kMessageDoc) winNameType = ksMssgName;
  748.  
  749.     err = AppNewDocument(newFrHndl, winNameType);
  750.     if (!err) {
  751.         oldMoves = (*oldFrHndl)->doc.gameMoves;
  752.         newMoves = (**newFrHndl)->doc.gameMoves;
  753.         oldMovesSize = GetHandleSize((Handle)oldMoves);
  754.         SetHandleSize((Handle)newMoves, oldMovesSize);
  755.         err = MemError();
  756.         if (!err) {
  757.             ptr1     = (Ptr)&((*oldFrHndl)->doc);
  758.             ptr2     = (Ptr)&((*oldFrHndl)->doc.endFileInfo1);
  759.             dataSize = (long)ptr2 - (long)ptr1;
  760.             ptr2     = (Ptr)&((**newFrHndl)->doc);
  761.             BlockMove(ptr1, ptr2, dataSize);
  762.             (**newFrHndl)->doc.timeLeft[0] = (**newFrHndl)->doc.timeLeft[1] = -1;
  763.             BlockMove((Ptr)*oldMoves, (Ptr)*newMoves, oldMovesSize);
  764.             if ((*oldFrHndl)->doc.myColor == kMessageDoc) {
  765.                 te = (*oldFrHndl)->doc.message[kMessageOut];
  766.                 oldText = (*te)->hText;
  767.                 newText = (Handle)(**newFrHndl)->doc.legalMoves;
  768.                 SetHandleSize(newText, (*te)->teLength);
  769.                 err = MemError();
  770.                 if (!err) BlockMove(*oldText, *newText, (*te)->teLength);
  771.             }
  772.         }
  773.     }
  774.     return(err);
  775. }
  776.  
  777.  
  778.  
  779. /*****************************************************************************/
  780.  
  781.  
  782.  
  783. OSErr    AppAutoLaunch(FileRecHndl frHndl)
  784. {
  785.     OSErr            err;
  786.     AEDesc            remoteDesc, aeDirDesc, listElem, fileList;
  787.     AppleEvent        aevt, aeReply;
  788.     char            hstate;
  789.     Str255            path;
  790.     Str255            app;
  791.     AliasHandle        dirAlias, fileAlias;
  792.  
  793.     err = noErr;
  794.  
  795.     if ((*frHndl)->doc.reconnectZone[0]) {
  796.  
  797.         DoSetCursor(*GetCursor(watchCursor));
  798.  
  799.         if (!GetRemoteProcessTarget(frHndl, &remoteDesc, FinderFilter)) {
  800.  
  801.             err = AECreateAppleEvent('FNDR', 'sope', &remoteDesc,
  802.                                       kAutoGenerateReturnID, kAnyTransactionID, &aevt);
  803.             AEDisposeDesc(&remoteDesc);
  804.  
  805.             if (!err) {
  806.  
  807.                 hstate = LockHandleHigh((Handle)frHndl);
  808.                 pcpy(path, (*frHndl)->doc.reconnectPath);
  809.                 pcpy(app, path);
  810.                 pcat(app,  (*frHndl)->doc.reconnectApp);
  811.                 HSetState((Handle)frHndl, hstate);
  812.                 NewAliasMinimalFromFullPath(path[0], (path + 1), "\p", "\p", &dirAlias);
  813.                 NewAliasMinimalFromFullPath(app[0],  (app + 1),  "\p", "\p", &fileAlias);
  814.  
  815.                 err = AECreateList(nil, 0, false, &fileList);
  816.  
  817.                 if (!err) {
  818.                     hstate = LockHandleHigh((Handle)dirAlias);
  819.                     err = AECreateDesc(typeAlias, (Ptr)*dirAlias,
  820.                                        GetHandleSize((Handle)dirAlias), &aeDirDesc);
  821.                     HSetState((Handle)dirAlias, hstate);
  822.                 }
  823.                 DisposeHandle((Handle)dirAlias);
  824.  
  825.                 if (!err) {
  826.                     err = AEPutParamDesc(&aevt, keyDirectObject, &aeDirDesc);
  827.                     AEDisposeDesc(&aeDirDesc);
  828.                 }
  829.  
  830.                 if (!err) {
  831.                     hstate = LockHandleHigh((Handle)fileAlias);
  832.                     err = AECreateDesc(typeAlias, (Ptr)*fileAlias,
  833.                                        GetHandleSize((Handle)fileAlias), &listElem);
  834.                     HSetState((Handle)dirAlias, hstate);
  835.                 }
  836.                 DisposeHandle((Handle)fileAlias);
  837.  
  838.                 if (!err) {
  839.                     err = AEPutDesc(&fileList, 0, &listElem);
  840.                     AEDisposeDesc(&listElem);
  841.                 }
  842.  
  843.                 if (!err) {
  844.                     err = AEPutParamDesc(&aevt, 'fsel', &fileList);
  845.                     AEDisposeDesc(&fileList);
  846.                 }
  847.  
  848.                 if (!err) {
  849.                     err = AESend(&aevt, &aeReply,
  850.                                 (kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer),
  851.                                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  852.                     AEDisposeDesc(&aeReply);
  853.                 }
  854.  
  855.                 AEDisposeDesc(&aevt);
  856.  
  857.                 if (!err) SendGame(frHndl, kIsMove, "\pKibitz");
  858.  
  859.             }
  860.         }
  861.     }
  862.  
  863.     return(err);
  864. }
  865.  
  866.  
  867.  
  868.